import java.util.StringTokenizer;

/*
 * Data class that does the
 * marshalling and unmarshalling
 * and handles the String messages
 */
public class Data {
	
	public static final int REQUEST_MSG = 1;//Sent by Client
	public static final int REPLY_MSG = 2;//Sent by server
	
	public static final int READ_OP = 1;
	public static final int WRITE_OP = 2;
	public static final int MONITOR_OP = 3;
	public static final int CREATE_OP = 4;
	public static final int APPEND_OP = 5;
	public static final int VALIDATE_OP = 6;
	public static final int CLOSE_OP = 7;
	public static final int END_MONITOR_OP = 8;
	//Server operations	
	public static final int UPDATE_OP = 9;
	public static final int ERROR_OP = 10;
	
	private static final int FILENAME = 0;
	private static final int OFFSET = 1;
	private static final int CONTENTS = 2;
	private static final int T_MSERVER = 3;
	private static final int INTERVAL = 4;
	private static final int ERROR = 5;
	
	private String msgStr = "";
	
	private int mID;
	private int messageType;
	private int operation;
	private int length;
	private String[] args;
	
	/**
	* Scramble the message into a whole String
	*/
	public Data(int mID, int messageType, int operation) {
		this.mID = mID;
		this.messageType = messageType;
		this.operation = operation;
		int argsLength = getArgsLength();
		this.length = 4+argsLength;
		msgStr = mID +"|"+ messageType +"|"+ operation +"|"+ length;
		//System.out.println("DEBUG: (Before args)msgStr="+msgStr);
		setArgsLength(argsLength);
	}
	
	/**
	* Unscramble the message given the whole String
	*/
	public Data(String msgStr) {
		this.msgStr = msgStr;
		System.out.println("DEBUG: msgStr="+msgStr);
		String[] arr = msgStr.split("\\|");
		//System.out.println("DEBUG: split arr length=" + arr.length);
		//Split string and save variables	
		mID = Integer.parseInt(arr[0]);
		//System.out.println("mID="+mID);
		messageType = Integer.parseInt(arr[1]);
		//System.out.println("messageType="+messageType);
		operation = Integer.parseInt(arr[2]);
		//System.out.println("operation="+operation);
		length = Integer.parseInt(arr[3]);
		//int cargsLength = length - 4;
		//System.out.println("length="+length);
		//System.out.println("cargsLength="+cargsLength);
		int argsLength = getArgsLength();
		args = new String[argsLength];
		for(int i=0; i<argsLength; i++) {
			args[i] = arr[4+i];
			//System.out.println("DEBUG: "+i+" = "+arr[i+4]+"END");
		}
	}
	
	private void setArgsLength(int argsLength) {
		args = new String[argsLength];
	}
	
	private int getArgsLength() {
		switch(operation) {
			case READ_OP:
				if(messageType == REQUEST_MSG) {
					return 1;
				} else {
					return 2;
				}
			case WRITE_OP:
				if(messageType == REQUEST_MSG) {
					return 3;
				} else {
					return 2;
				}
			case MONITOR_OP:
				if(messageType == REQUEST_MSG) {
					return 2;
				}
			case CREATE_OP:
				if(messageType == REQUEST_MSG) {
					return 1;
				} else {
					return 1;
				}
			case APPEND_OP:
				if(messageType == REQUEST_MSG) {
					return 2;
				} else {
					return 2;
				}
			case VALIDATE_OP:
				if(messageType == REQUEST_MSG) {
					return 1;
				} else {
					return 1;
				}
			case UPDATE_OP:
				if(messageType == REPLY_MSG) {
					return 2;
				}
			case ERROR_OP:
				if(messageType == REPLY_MSG) {
					return 1;
				}
		}
		return 0;
	}
	
   /**
	* Method that gets the index of args array
	* for the different arguments
	* as different messages are arranged differently
	*/
	private int getIndex(int item) {
		switch(item) {
			case FILENAME:
				if(messageType == REQUEST_MSG && 
					(operation == READ_OP 
					|| operation == WRITE_OP 
					|| operation == MONITOR_OP 
					|| operation == CREATE_OP 
					|| operation == VALIDATE_OP
					|| operation == APPEND_OP)) {
					return 0;
				}
				break;
			case OFFSET:
				if(messageType == REQUEST_MSG &&
					operation == WRITE_OP) {
					return 1;
				}
				break;
			case CONTENTS:
				if(messageType == REQUEST_MSG) {
					if(operation == WRITE_OP) {
						return 2;
					} else if(operation == APPEND_OP) {
						return 1;
					} 
				} else if(messageType == REPLY_MSG) {
					if(operation == READ_OP 
					|| operation == WRITE_OP
					|| operation == UPDATE_OP
					|| operation == APPEND_OP) {
						return 1;
					}
				}
				break;
			case T_MSERVER:
				if(messageType == REPLY_MSG && 
					(operation == READ_OP 
					|| operation == WRITE_OP 
					|| operation == UPDATE_OP
					|| operation == CREATE_OP
					|| operation == VALIDATE_OP
					|| operation == APPEND_OP)) {
					return 0;
				} else if(messageType == REQUEST_MSG &&
							operation == VALIDATE_OP) {
					return 1;
				}				
				break;
			case INTERVAL:
				if(messageType == REQUEST_MSG &&
					operation == MONITOR_OP) {
					return 1;
				}
				break;
			case ERROR:
				if(messageType == REPLY_MSG && 
					operation == ERROR_OP ) {
					return 0;
				}
		}
		return -1;
	}
	
   /**
	* Method that returns the whole String of the message
	*/
	public String getMessageStr() {
		//Add arguments
		String arguments = "";
		/*0-filename 1-offset 2-contents 
		3-t_mserver 4-interval 5-errormsg*/
		switch(operation) {
			case READ_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)];
				} else {
					arguments += args[getIndex(T_MSERVER)] 
						+"|"+ args[getIndex(CONTENTS)];
				}
				break;
			case WRITE_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)] 
						+"|"+ args[getIndex(OFFSET)] 
						+"|"+ args[getIndex(CONTENTS)];
				} else {
					arguments += args[getIndex(T_MSERVER)] 
						+"|"+ args[getIndex(CONTENTS)];
				}
				break;
			case MONITOR_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)]
						+"|"+ args[getIndex(INTERVAL)];
				}
				break;
			case CREATE_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)];
				} else {
					arguments += args[getIndex(T_MSERVER)];
				}
				break;
			case APPEND_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)] 
						+"|"+ args[getIndex(CONTENTS)];
				} else {
					arguments += args[getIndex(T_MSERVER)]
						+"|"+ args[getIndex(CONTENTS)];
				}
				break;
			case VALIDATE_OP:
				if(messageType == REQUEST_MSG) {
					arguments += args[getIndex(FILENAME)];
				} else {
					arguments += args[getIndex(T_MSERVER)];
				}
				break;
			case UPDATE_OP:
				if(messageType == REPLY_MSG) {
					arguments += args[getIndex(T_MSERVER)] 
						+"|"+ args[getIndex(CONTENTS)];
				}
				break;
			case ERROR_OP:
				if(messageType == REPLY_MSG) {
					arguments += args[getIndex(ERROR)] ;
				}
				break;
		}
		msgStr += "|" + arguments + "|END";
		return msgStr;
	}
	
	public int getMID() {
		return mID;
	}
	
	public int getOperation() {
		return operation;
	}
	
	public String getFilename() {	
		return getArgs(getIndex(FILENAME));
	}
	
	public void setFilename(String fname) {
		args[getIndex(FILENAME)] = fname;
	}
	
	public int getOffset() {
		return Integer.parseInt(getArgs(getIndex(OFFSET)));
	}
	
	public void setOffset(int i) {
		args[getIndex(OFFSET)] = String.valueOf(i);
	}
	
	public String getFileContents() {
		return getArgs(getIndex(CONTENTS));
	}
	
	public void setFileContents(String contents) {
		args[getIndex(CONTENTS)] = contents;
	}
	
	public String getTMserver() {
		return getArgs(getIndex(T_MSERVER));
	}
	
	public void setTMServer(String t_m) {
		args[getIndex(T_MSERVER)] = t_m;
	}
	
	public int getInterval() {
		return Integer.parseInt(getArgs(getIndex(INTERVAL)));
	}
	
	public void setInterval(int interval) {
		args[getIndex(INTERVAL)] = Integer.toString(interval);
	}
	
	public String getErrorMsg() {
		return getArgs(getIndex(ERROR));
	}
	
	public void setErrorMsg(String msg) {
		args[getIndex(ERROR)] = msg;
	}
	
	private String getArgs(int index) {
		return args[index];
	}
	
}